package com.ybear.ybutils.utils;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.provider.MediaStore;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.collection.ArraySet;

import com.ybear.ybutils.utils.time.DateTime;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

/**
 * 存储工具类
 */
public class IOUtil {
    private static Thread mDeleteFileThread = null;
    private static LinkedList<String> mDeleteFilePathList;

    /**
     * 保存sp
     * @param context       上下文
     * @param cdName        名称
     * @param data          数据
     * @return              结果
     */
    public static boolean writeSharedPreferences(@NonNull Context context,
                                                 @NonNull String cdName,
                                                 @NonNull Map<String, Object> data) {
        SharedPreferences sp = context.getSharedPreferences(cdName, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        boolean isCommit;
        for( String key : data.keySet() ) {
            Object val = data.get( key );
            if( val == null ) continue;

            if( val instanceof Boolean ) {
                editor.putBoolean( key, Boolean.parseBoolean( val.toString() ) );
                continue;
            }
            if( val instanceof Float ) {
                editor.putFloat( key, Float.parseFloat( val.toString() ) );
                continue;
            }
            if( val instanceof Long ) {
                editor.putLong( key, Long.parseLong( val.toString() ) );
                continue;
            }
            if( val instanceof Integer ) {
                editor.putInt( key, Integer.parseInt( val.toString() ) );
                continue;
            }
            if( val instanceof Set ) {
                Set<String> aSet = new ArraySet<>();
                Iterator iterator = ((Set) val).iterator();
                if( iterator.hasNext() ) {
                    Object next = iterator.next();
                    if( next != null ) aSet.add( next.toString() );
                }
                editor.putStringSet( key, aSet );
                continue;
            }
            editor.putString( key, val.toString() );
        }
        isCommit = editor.commit();
        editor.clear();
        return isCommit;
    }

    /**
     * 获取sp
     * @param context       上下文
     * @param cdName        名称
     * @return              返回数据
     */
    public static Map<String, Object> readSharedPreferences(@NonNull Context context,
                                                            @NonNull String cdName) {
        return new HashMap<>( context.getSharedPreferences(cdName, Context.MODE_PRIVATE).getAll() );
    }

    /**
     * 删除sp
     * @param context       上下文
     * @param cdName        名称
     * @return              结果
     */
    public static boolean deleteSharedPreferences(@NonNull Context context,
                                                  @NonNull String cdName) {
        SharedPreferences sp = context.getSharedPreferences(cdName, Context.MODE_PRIVATE);
        return sp != null && sp.edit().clear().commit();
    }

    /**
     * 删除sp
     * @param context       上下文
     * @param cdName        名称
     * @param keys          删除的key
     * @return              结果
     */
    public static boolean deleteSharedPreferences(@NonNull Context context,
                                                  @NonNull String cdName,
                                                  @NonNull String... keys) {
        SharedPreferences sp = context.getSharedPreferences(cdName, Context.MODE_PRIVATE);
        if( sp == null ) return false;
        SharedPreferences.Editor editor = sp.edit();
        for( String k : keys ) editor.remove( k );
        return editor.commit();
    }


    /**
     * 保存图片到相册
     * @param context       上下文
     * @param title         标题
     * @param description   描述
     * @param data          图片
     * @return              保存成功返回路径，否则返回<code>null</code>
     */
    @UiThread
    public static String writeImageToDCIM(@NonNull Context context,
                                          @NonNull String title,
                                          @NonNull String description,
                                          @NonNull Bitmap data){
        return MediaStore.Images.Media.insertImage(
                context.getContentResolver(), data, title ,description
        );
    }

    /**
     * 删除文件
     * 该方法以线程的形式完成，多次调用仅运行一个线程，删除方式为队列
     * @param context       上下文
     * @param call          处理结果
     * @param paths         路径
     */
    public static void deleteFile(@NonNull Context context,
                                  @Nullable Comparator<Integer> call,
                                  String... paths) {
        if( paths == null || paths.length == 0 ) return;
        if( mDeleteFilePathList == null ) mDeleteFilePathList = new LinkedList<>();
        //添加路径
        for (String path : paths) mDeleteFilePathList.addLast( path );
        if( mDeleteFileThread != null ) return;
        //开启删除线程
        mDeleteFileThread = new Thread(() -> {
            int index = 0;
            int result = 0;
            while ( mDeleteFilePathList.size() != 0 ) {
                try {
                    String firstPath = mDeleteFilePathList.removeFirst();
                    //删除缩略图文件
                    File f = new File( firstPath );
                    if( f.exists() && f.delete() ) {
                        //删除残余文件
                        context.getContentResolver().delete(
                                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                                MediaStore.Images.Media.DATA + "=?",
                                new String[]{ firstPath }
                        );
                        result = 1;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    result = -1;
                } finally {
                    if( call != null ) call.compare( index++, result );
                }
            }
            mDeleteFileThread = null;
            mDeleteFilePathList = null;
            if( call != null ) call.compare( -1, -1 );
        });
        mDeleteFileThread.start();
    }

    public static void deleteFile(@NonNull Context context, String... paths) {
        deleteFile( context, null, paths );
    }

    /**
     * 保存文件
     * @param path          路径
     * @param fullName      全称 file_name.txt
     * @param data          数据
     * @param append        是否追加
     * @return              结果
     */
    public static boolean saveFile(String path,
                                   @Nullable String fullName,
                                   byte[] data,
                                   boolean append) {
        if( path == null ) return false;
        File f;
        if( fullName != null ) {
            String separ = File.separator;
            //斜杠判断
            if( !path.endsWith( separ ) && !fullName.startsWith( separ ) ) path += separ;
            f = new File( path + fullName );
        }else {
            f = new File( path );
        }
        FileWriter fw = null;
        //文件是否存在，创建目录
        if( !f.exists() && new File( path ).mkdirs() ) {
            try {
                //创建文件
                if( !f.createNewFile() ) return false;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            fw = new FileWriter( f, append );
            for( byte b : data ) fw.write( (int) b );
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if( fw != null ) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * 保存文件
     * @param path          路径
     * @param fullName      全称 file_name.txt
     * @param data          数据
     * @return              结果
     */
    public static boolean saveFile(String path, String fullName, byte[] data) {
        return saveFile( path, fullName, data, false );
    }

    /**
     * 保存文件
     * @param fullPath      完整路径
     * @param data          数据
     * @param append        是否追加
     * @return              结果
     */
    public static boolean saveFile(String fullPath, byte[] data, boolean append) {
        return saveFile( fullPath, null, data, append );
    }

    /**
     * 保存文件
     * @param fullPath      完整路径
     * @param data          数据
     * @return              结果
     */
    public static boolean saveFile(String fullPath, byte[] data) {
        return saveFile( fullPath, null, data, false );
    }

    /**
     * 保存日志文件
     * @param context       上下文
     * @param name          日志名
     * @param data          数据
     * @return              结果
     */
    public static boolean saveLogFile(Context context, String name, String data, boolean append) {
        File f = context.getExternalFilesDir(null);
        char sc = File.separatorChar;
        //设置保存文件路径
        String path = f != null ? f.getAbsolutePath() + sc + "logs" + sc : null;
        //保存文件
        return saveFile( path, name, data.getBytes(), append );
    }

    /**
     * 保存日志文件
     * @param context       上下文
     * @param data          数据
     * @param append        是否追加
     * @return              结果
     */
    public static boolean saveLogFile(Context context, String data, boolean append) {
        long millis = System.currentTimeMillis();
        return saveLogFile(
                context,
                String.format( "%s_%s.log", DateTime.parse( millis ), millis ),
                data,
                append
        );
    }

    /**
     * 保存日志文件
     * @param context       上下文
     * @param data          数据
     * @return              结果
     */
    public static boolean saveLogFile(Context context, String data) {
        return saveLogFile( context, data, false );
    }
}
